home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / sos3-2.lha / src / psm / psm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-05  |  63.5 KB  |  1,960 lines

  1. /* --------------------------------------------------------------------------
  2.  * Copyright 1992 by Forschungszentrum Informatik (FZI)
  3.  *
  4.  * You can use and distribute this software under the terms of the licence
  5.  * you should have received along with this program.
  6.  * If not or if you want additional information, write to
  7.  * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
  8.  * D-7500 Karlsruhe 1, Germany.
  9.  * --------------------------------------------------------------------------
  10.  */
  11. // **************************************************************************
  12. // Module psm                                  Emil Sekerinski, Walter Zimmer
  13. //
  14. // **************************************************************************
  15. //  persistent storage manager: implementation 
  16. // **************************************************************************
  17.  
  18. //#define LOCKD_CORRECT
  19. /*
  20.    if defined
  21.    then fcntl is used for container locking
  22.    else flock is used for container locking
  23.    fi
  24.  
  25.    As discussed in README.install, the default is "flock" (LOCKD_CORRECT not
  26.    defined), because of a bug in the SunOS lock demon.
  27.    The constant is set in the SOS Makefile when this file is compiled. See
  28.    the macro USE_FCNTL there.
  29. */
  30.  
  31. #include <sys/file.h>
  32. #include <osfcn.h>
  33. #include <libc.h>
  34. #include <errno.h>
  35. #include <sys/param.h>
  36. #include <string.h>
  37.  
  38. // *** necessary (and only allowed) when using  ATT 2.0 ***
  39. // #include <sys/time.h>
  40.  
  41. #ifndef SEEK_SET
  42. #define SEEK_SET    L_SET
  43. #define SEEK_CUR    L_INCR
  44. #define SEEK_END    L_XTND
  45. #endif
  46.  
  47.  
  48. #include "psm.h"
  49. #include "psm_err.h"   // err_raise, err_SYS
  50. #include "trc_psm.h"   // trace-module; numbers 11(H) -14(VL) + psm_CHECK
  51. #ifdef MONITOR
  52. #include "mon.h"       // mon_Window,mon_create,mon_black,mon_white,mon_close
  53. #endif
  54. #include "knl_use.h"   // 
  55.  
  56. // *******************   const definitions   *********************************
  57.  
  58. const UNUSED=0;        //  used for id's (value must be zero !)
  59. const UNDEF=-1;        //  used fur fileindex, bufferindex (also for fd in open())
  60.                        // for test, if object still exists or not (see list
  61.                //  free blocks)
  62.  
  63. const SIZEOF_INT = 4;        // if this is not valid => psm must be rewritten (!)
  64. const C=61;                  // container table size (max. number of open containers)
  65. const P=1024;                // page size in bytes
  66. const int DEFAULT_BUFFERSIZE = 128;    // def. size for paging buffer (can be
  67.                                        // changed by SOSBUFFERSIZE/MONITOR)
  68. const N=(P/SIZEOF_INT-4)/2; // =#pagetable entries per page and version
  69.                              // =#container pages between pagetable pages
  70. const MAX_FREEBLOCK_LENGTH = P - 1 * SIZEOF_INT; // maximum for the length
  71.                          // of a free block
  72. const SWITCH_OFFSET = 0;    // offset of switch in containerfile
  73. const err_msg ERR="container manager";
  74.  
  75. const sos_Container TEMP_CONTAINER=sos_Container::make (0);
  76. const sos_Container ROOT_CONTAINER=sos_Container::make (1);
  77. const sos_Container UNUSED_CONTAINER=sos_Container::make (0xffffffff); //2^32-1
  78. const sos_Offset ROOT_OFFSET=P; // bytes 0..P-1 used for table of free blocks.
  79.  
  80. // *******************   header variable definition  **************************
  81.  
  82. struct containerinfo 
  83. {
  84.     int id;        // 1<=id<2^24-1 or id==UNUSED
  85.     int status;        // container status: READABLE or WRITEABLE or CHECKEDOUT
  86.     int fd;        // file descriptor of container file
  87.     int sw;        // upper/lower pagetable switch for current version
  88.     int ubfreesize;    // upper bound (approximative) of the size of all free blocks,
  89.             // used for searching free blocks more efficiently
  90.     int contpages;    // number of container pages of current version
  91.     int conttablesize;    // size of the three subsequent arrays,must be multiple of N
  92.             // ( >= contpages)
  93.     int *bufferindex;    // maps [0..contpages) to [0..B)+UNDEF
  94.     int *fileindex;    // maps [0..contpages) to [0..filepages)+UNDEF (page table)
  95.     int *shadowed;    // maps [0..contpages) to bool
  96.             // (indicates, if shadow page exist)
  97.     int filepages;    // file pages occupied by the current container file
  98.             // (upper bound for reference from fileindex to containerpage)
  99.     int filetablesize;  // size of freefilepage array ( >= filepages )
  100.     int *freefilepage;  // maps [0..filepages) to bool, i.e., indicates the free
  101.                         // pages in the container file
  102.     int freefilepage_index;  // index to make search for next freefilepage more 
  103.                  // efficient; points to last found empty page (in 
  104.                  // the beginning => -1)
  105. #ifdef MONITOR
  106.     mon_Window win;
  107. #endif
  108. };
  109. static containerinfo containertable[C]; // `hash` table for container entries
  110.  
  111. static int B;     // number of pages in buffer, 1 <= B <= Bmax
  112. struct bufinfo   // info for each page in buf[0..B)
  113. {
  114.     int id, page;    // backward reference to container id and container page,
  115.                      // used for page replacement: id==UNUSED || (id==
  116.                  // containertable[?].id && 0<=page<containertable[?].contpages)
  117.     int referenced;  // used for page replacement (second chance algorithm)
  118.     int modified;    // indicates that page has to be written on commit
  119. };
  120.  
  121. static int buftable_index = 0;      // buffer table index : used for page replacement
  122.  
  123. typedef char PAGE[P];
  124.  
  125. static PAGE *buf;               // internal buffer for paging 
  126. static bufinfo *buftable;       // table of infos for each page of the buffer
  127.  
  128.  
  129. #ifdef MONITOR
  130. static int monactivated;
  131. #endif
  132.  
  133. // err_buffer is used for variable error messages
  134. // current use only in : lookupcontainer
  135. static char err_buffer[150];  
  136.  
  137. static struct initialize 
  138. {   // calls automatically psm_initialize when main program starts, because
  139.     // initialize() is constructor of struct initialize (standard trick)
  140.  
  141. initialize() {psm_initialize();} 
  142. } dummy;
  143.  
  144.  
  145. //-----------------------------------------------------------------------------
  146.  
  147. void psm_initialize() 
  148. {
  149.    B = DEFAULT_BUFFERSIZE;  // normal value of B if not monitoring 
  150.                 //                   &&  SOSBUFFERSIZE not set
  151.  
  152.    char* bufsize = getenv("SOSBUFFERSIZE");
  153.    if (bufsize != 0)   // SOSBUFFERSIZE is set
  154.    {
  155.       sscanf(bufsize,"%d",&B);
  156.       if (B <= 0)
  157.      B = DEFAULT_BUFFERSIZE;
  158.    }
  159.  
  160. #ifdef MONITOR
  161. monactivated = FALSE;
  162. char* e = getenv("SOSMONITOR");
  163. if (e != 0)
  164. {
  165.     sscanf(e,"%d",&B);
  166.     if (B > 0)
  167.     {
  168.     mon_initialize();
  169.     monactivated = TRUE;
  170.     }
  171.     else 
  172.        B = DEFAULT_BUFFERSIZE;
  173. }
  174. #endif
  175.  
  176. #if BOOT
  177.     srandom(1);
  178. #else
  179.     timeval tp;
  180.     gettimeofday(&tp,0);
  181.     srandom((int)tp.tv_sec);
  182. #endif
  183.  
  184.    buftable  = new bufinfo [B];                      // allocation of buffers
  185.    buf = new PAGE [B];
  186.  
  187.    int i,j;                             // initialization of buffers and tables
  188.    for (i = 0; i < C; i++) containertable[i].id = UNUSED;
  189.    for (i = 0; i < B; i++) buftable[i].id = UNUSED;
  190.    for (i = 0; i < B; i++) 
  191.       for (j = 0; j < P; j++) buf[i][j] = UNUSED;
  192.  
  193. }
  194.  
  195. //--------------------------------------------------------------------------
  196. // auxiliary functions   ( and inline functions )
  197. //--------------------------------------------------------------------------
  198.  
  199. inline int min(int a, int b) 
  200. {
  201.     return (a < b ? a : b); 
  202. }
  203.  
  204. inline int max(int a, int b) 
  205. {
  206.     return (a > b ? a : b); 
  207. }
  208.  
  209. inline int offrounded_pagenumber(int size)  // returns floor(size/P)
  210. {
  211.    return (int)(size / P);
  212. }
  213.  
  214. inline int uprounded_pagenumber(int size)   // returns ceil(size/P)
  215. {
  216.    return (int)((size + P - 1) / P);
  217. }
  218.  
  219. inline int N_upround(int nr)            // returns the next multiple of N
  220. {
  221.    return ((nr + N - 1) / N) * N;
  222. }
  223.  
  224. //--------------------------------------------------------------------------
  225.  
  226. inline int pagetable_offset(int page, int sw)
  227. {
  228.    // return offset of pagetable in containerfile, which contains entry for `page`.
  229.    // addition of offsets for
  230.    //  (1) page of pagetable  
  231.    //  (2) offset inside of this page (old or new pagetable)
  232.  
  233.    return (int)( (page/N) * (N+1) * P   +  (sw ? 4 : 4 + N) * SIZEOF_INT);
  234. }
  235. //--------------------------------------------------------------------------
  236.  
  237. inline int contpages_offset(int sw)
  238. {
  239.    return (int)( (sw ? 1 : 2) * SIZEOF_INT );
  240. }
  241. //--------------------------------------------------------------------------
  242. //--------------------   end of inline functions   -------------------------
  243. //--------------------------------------------------------------------------
  244.  
  245.  
  246.  
  247. static unsigned used_pages(containerinfo &ci) 
  248. {
  249.     // returns number of occupied pages (referenced from fileindex) 
  250.     // containerfile is normally larger than necessary because of unused
  251.     // pages and  shadowed pages (if container is open)
  252.  
  253.     unsigned used_pags = 0;
  254.     for (int p = 0; p < ci.contpages; p++)
  255.     if (ci.fileindex[p] != UNDEF) used_pags++;
  256.     return used_pags; 
  257. }
  258.  
  259. //--------------------------------------------------------------------------
  260.  
  261. static unsigned free_pages(containerinfo &ci) 
  262. {
  263.     // returns number of free places (UNDEF) in fileindex 
  264.  
  265.     return (ci.contpages - used_pages(ci)); 
  266. }
  267.  
  268. //------------------------------------------------------------------------------
  269.  
  270. static int lock(int fd, sos_Access_mode am, sos_Sync_mode sm) 
  271. {
  272.     T_PROC ("psm::lock");
  273.     TT (psm_H, T_ENTER; TI((int)fd);TI((int)am);TI((int)sm));
  274. /*
  275.     This version of lock uses the nfs locking mechanism via fcntl. Due to
  276.     bugs in the implementation, it may cause in a network of sun3 and sun4
  277.     stations the file server to crash !
  278. */
  279.  
  280. #ifdef LOCKD_CORRECT
  281.  
  282.     struct flock fl;
  283.     fl.l_type = (am == READING ? F_RDLCK : F_WRLCK);
  284.     fl.l_whence = 0; //starting offset = start of file
  285.     fl.l_start = 0;  //relative_offset=0
  286.     fl.l_len = 0;    //to end of file
  287.     int cmd = (sm == TESTING ? F_SETLK : F_SETLKW);
  288.     return fcntl(fd, cmd, (int)&fl) != -1;
  289.  
  290. /*
  291.     This version of lock sets the locks via flock. Locks obtained through
  292.     flock are only known to the system on which they are placed. Thus
  293.     inconsistencies may arise if the file is accessed via nfs from different
  294.     stations.
  295. */
  296.  
  297. #else
  298.  
  299.     int access = (am == READING ? LOCK_SH : LOCK_EX);
  300.     int sync = (sm == WAITING ? 0 : LOCK_NB);
  301.     TT (psm_H, T_LEAVE);
  302.     return flock(fd, access | sync) == 0;
  303.  
  304. #endif LOCKD_CORRECT
  305. }
  306.  
  307. //------------------------------------------------------------------------------
  308.  
  309. inline containerinfo* containertable_pos(int id)
  310. {
  311.     // returns containertable entry with key `id` (id == UNUSED == 0
  312.     // possible, see newcontainer), if container with `id` is opened, else UNDEF
  313.  
  314.     containerinfo *start, *probe;
  315.     probe =
  316.     start = &containertable[id % C];
  317.                   // in most cases a good starting point (see newcontainer)
  318.     do
  319.     {  if (probe->id == id) return probe;
  320.        probe = (probe == containertable) ? &containertable[C-1]
  321.                      : -- probe;
  322.     } while (probe != start);
  323.  
  324.     return (containerinfo *)UNDEF;
  325. }
  326.  
  327. //------------------------------------------------------------------------------
  328.  
  329.  
  330. inline int container_is_open(int id) 
  331. {
  332.     // returns TRUE, if its status equals  READABLE, WRITEABLE, CHECKEDOUT
  333.     // or DESTROYED, i.e. , if 'id' is in containertable
  334.  
  335.     return (containertable_pos(id) != (containerinfo *)UNDEF);
  336. }
  337.  
  338. //------------------------------------------------------------------------------
  339.  
  340. static containerinfo &newcontainer(int id) 
  341. {
  342.     containerinfo *start, *probe;
  343.     probe =
  344.     start = &containertable[id % C];
  345.         // in most cases a good starting point (see containertable_pos)
  346.     do
  347.     {  if (probe->id == UNUSED) return *probe;
  348.        probe = (probe == containertable) ? &containertable[C-1]
  349.                      : -- probe;
  350.     } while (probe != start);
  351.  
  352.     err_raise(err_SYS,err_PSM_CONTAINER_TABLE_FULL,ERR,FALSE);
  353.     return containertable[0];  // never reached! - only to avoid warnings
  354. }
  355.  
  356. //------------------------------------------------------------------------------
  357.  
  358. static containerinfo &lookupcontainer (int id,
  359.                        int open_on_read,
  360.                        int check_if_writing,
  361.                        int destroyed_permitted = FALSE) 
  362. {
  363.    // gives back the index in the containertable
  364.    // if container not in the containertable and open_on_read
  365.    //    -> implicit open if possible
  366.    // check_if_writing to control, whether the user has write permission
  367.    // destroyed_permitted  only is TRUE for operations, for which
  368.    // operations on destroyed containers are allowed 
  369.    // (destroy, close, commit, reset ; status, exists, object_exists)
  370.  
  371.    containerinfo *ct = containertable_pos(id);
  372.  
  373.    if (ct == (containerinfo *)UNDEF)
  374.       if (open_on_read)
  375.      if (sos_Container::make(id).open(READING,WAITING)==OPENED)
  376.          return lookupcontainer(id,FALSE,FALSE);
  377.      else
  378.      {   // 36 characters, 20 reserved for %d's, 70 for %s <= 150 characters
  379.          sprintf(err_buffer,"cannot open container %d\n\tUnix error %d : %.70s", id, errno,
  380.          (0 <= errno && errno < sys_nerr) ? sys_errlist[errno]
  381.                               : "***");
  382.          err_raise(err_SYS,err_buffer,ERR,FALSE);
  383.      }
  384.       else err_raise(err_SYS,err_PSM_UNOPENED_CONTAINER,ERR,FALSE);
  385.    else
  386.      if (ct->status == DESTROYED)
  387.         if (destroyed_permitted)
  388.        return *ct;  // avoid check_if_writing
  389.     else
  390.        err_raise(err_SYS,err_PSM_DESTROYED_CONTAINER,ERR,FALSE);
  391.  
  392.    if (check_if_writing  &&  ct->status != WRITEABLE)
  393.       err_raise(err_SYS,err_PSM_NONWRITEABLE_CONTAINER,ERR,FALSE);
  394.    return *ct; 
  395. }
  396.  
  397. //------------------------------------------------------------------------------
  398.  
  399. static void extendtable(int *&tab, int size, int newsize) 
  400. {  
  401.     int *newtab = new int[newsize];
  402.     for (int i = 0; i < size; i++) newtab[i] = tab[i];
  403.     for (i = size; i < newsize; i++) newtab[i] = 0;  // initialize with zero
  404.     delete tab;
  405.     tab = newtab;
  406. }
  407.  
  408. //------------------------------------------------------------------------------
  409.  
  410. static void calculatefreefilepages(containerinfo &ci) 
  411. {
  412.     // calculates ci.freefilepage, ci.filepages and clears ci.shadowed
  413.     // used only in readpagetable/writepagetable => ci.shadowed[]=FALSE
  414.  
  415.     for (int p = 0; p < ci.filetablesize; p++) ci.freefilepage[p] = TRUE;
  416.     ci.filepages = 0;
  417.     for (p = 0; p < ci.contpages; p++)
  418.     {   if (ci.fileindex[p] != UNDEF)
  419.     {   ci.freefilepage[ci.fileindex[p]] = FALSE;
  420.             ci.filepages = max (ci.filepages,ci.fileindex[p] + 1);
  421.     }
  422.         ci.shadowed[p] = FALSE; 
  423.     } 
  424. }
  425.  
  426.  
  427. //------------------------------------------------------------------------------
  428.  
  429. static int findfreefilepage(containerinfo &ci)
  430.     // returns number of first free file page, mark it as used
  431.     // and increment (if necessary) ci.filepages
  432.  
  433.     if (ci.filepages > 0)
  434.        ci.freefilepage_index = (ci.freefilepage_index + 1) % ci.filepages; 
  435.     else 
  436.        ci.freefilepage_index = 0;
  437.  
  438.     // "+1" for next possibly empty filepage; "% ci.filepages"
  439.     // because in writepagetable (in commit) the container can be truncated
  440.     // (decrease ci.filepages) and the ci.freefilepage_index can so point 
  441.     // to a location outside the container area
  442.  
  443.     int p = 0;
  444.     while (p < ci.filepages  &&  ! ci.freefilepage[ci.freefilepage_index])
  445.     {   p++;
  446.        ci.freefilepage_index = (ci.freefilepage_index + 1) % ci.filepages;
  447.     }
  448.  
  449.     if (p == ci.filepages)   // no free page found (else freefilepage_index
  450.                  // points to a free page)
  451.     {   if (ci.filetablesize == p)
  452.     {   extendtable(ci.freefilepage,p,2*p);
  453.             ci.filetablesize *= 2;
  454.     }
  455.         ci.filepages++; 
  456.     ci.freefilepage_index = p;
  457.     }
  458.  
  459.     ci.freefilepage[ci.freefilepage_index] = FALSE;
  460.     return ci.freefilepage_index; }
  461.  
  462. //------------------------------------------------------------------------------
  463.  
  464. static int fileposition(int filepage) 
  465. {   
  466.     // the term filepage/N+1 adjusts for the pages of the 
  467.     // "page table" scattered in the container file
  468.     // pages ( = filepage) +  pages of pagetable( = filepage/N)
  469.     //                    + rootoffset (1 = table of free blocks) 
  470.  
  471.     return (filepage + filepage/N + 1) * P; 
  472. }
  473.  
  474. //------------------------------------------------------------------------------
  475.  
  476. static void readpage(containerinfo &ci, int contpage, int bufpage)
  477. {
  478.     int filepage = ci.fileindex[contpage];
  479.     if (filepage == UNDEF) err_raise(err_SYS,err_PSM_WRONG_OFFSET,ERR,FALSE);
  480.     lseek(ci.fd, fileposition(filepage), SEEK_SET);
  481.     read(ci.fd, buf[bufpage], P); 
  482. }
  483.  
  484. //------------------------------------------------------------------------------
  485.  
  486. static void writepage(containerinfo &ci, int contpage, int bufpage)
  487. {
  488.     int &filepage = ci.fileindex[contpage];
  489.     if (filepage == UNDEF) err_raise(err_SYS,err_PSM_WRITEPAGE,ERR,FALSE);
  490.     if ( ! ci.shadowed[contpage])
  491.     {   filepage = findfreefilepage(ci);
  492.         ci.shadowed[contpage] = TRUE; 
  493.     }
  494.     lseek(ci.fd, fileposition(filepage), SEEK_SET);
  495.     write(ci.fd, buf[bufpage], P);
  496. }
  497.  
  498. //------------------------------------------------------------------------------
  499.  
  500. static int preemptpage(int id, int contpage) 
  501. {
  502.     // choose buffer page according to the second chance algorithm,
  503.     // write chosen page back to container file if necessary and
  504.     // mark chosen buffer page as used for 'contpage' of container 'id'.
  505.  
  506.     while (buftable[buftable_index].referenced)
  507.     { 
  508.     buftable[buftable_index].referenced = FALSE;
  509.         buftable_index =(buftable_index + 1) % B; 
  510.     }
  511.    if (buftable[buftable_index].id != UNUSED) 
  512.    {    containerinfo &ci = lookupcontainer(buftable[buftable_index].id,FALSE,FALSE);
  513.         if (buftable[buftable_index].modified)
  514.        writepage(ci,buftable[buftable_index].page,buftable_index);
  515.         ci.bufferindex[buftable[buftable_index].page] = UNDEF;
  516. #ifdef MONITOR
  517.         if (monactivated) mon_white(ci.win,buftable[buftable_index].page);
  518. #endif
  519.     }
  520.     buftable[buftable_index].id = id;
  521.     buftable[buftable_index].page = contpage;
  522.     buftable[buftable_index].modified = FALSE;
  523.     int result = buftable_index;
  524.     buftable_index = (buftable_index + 1) % B;
  525.     return result; }
  526.  
  527. //------------------------------------------------------------------------------
  528.  
  529. static int lookuppage(containerinfo &ci, int contpage) 
  530. {
  531.     // return index of buffer page of container ci's contpage
  532.     // if contpage not already in buffer, read it from the container file
  533.     // by swapping it with another container page if necessary.
  534.  
  535.     if (contpage >= ci.contpages) err_raise(err_SYS,err_PSM_WRONG_OFFSET,ERR,FALSE);
  536.     int &bufpage = ci.bufferindex[contpage];
  537.     if (bufpage == UNDEF)
  538.     {   bufpage = preemptpage(ci.id,contpage);
  539. #ifdef MONITOR
  540.         if (monactivated) mon_black(ci.win,contpage);
  541. #endif
  542.         readpage(ci,contpage,bufpage); 
  543.     }
  544.     buftable[bufpage].referenced = TRUE;
  545.     return bufpage; 
  546. }
  547.  
  548. //------------------------------------------------------------------------------
  549.  
  550. static int readint(containerinfo &ci, sos_Offset o)
  551. {
  552.     // pre: o%P+SIZEOF_INT<=P, i.e. data does not cross page boundary
  553.  
  554.     return * (int*) &buf[lookuppage(ci,o/P)][o%P]; 
  555. }
  556.  
  557. //------------------------------------------------------------------------------
  558.  
  559. static void writeint(containerinfo &ci, sos_Offset o, int a) 
  560. {
  561.     // pre: o%P+SIZEOF_INT<=P, i.e. data does not cross page boundary
  562.  
  563.     int bufpage = lookuppage(ci,o/P);
  564.     * (int*) &buf[bufpage][o%P] = a;
  565.     buftable[bufpage].modified = TRUE;
  566. }
  567.  
  568. //------------------------------------------------------------------------------
  569.  
  570. static void readfrompage(containerinfo &ci, int page, int disp, int len, void *data)
  571. {
  572.     // pre: disp+len<=P, i.e. data does not cross page boundary
  573.  
  574.     bcopy(&buf[lookuppage(ci,page)][disp], data, len); 
  575. }
  576.  
  577. //------------------------------------------------------------------------------
  578.  
  579. static void writetopage(containerinfo &ci, int page, int disp, int len, void *data) 
  580. {
  581.     // pre: disp+len<=P, i.e. data does not cross page boundary
  582.  
  583.     int bufpage = lookuppage(ci,page);
  584.     bcopy(data, &buf[bufpage][disp], len);
  585.     buftable[bufpage].modified = TRUE;
  586. }
  587.  
  588. //------------------------------------------------------------------------------
  589.  
  590. static void readpagetable(containerinfo &ci) 
  591. {
  592.     // read ci.sw, ci.contpages, ci.fileindex from container file,
  593.     // calculate ci.freefilepage, ci.filepages,
  594.     // clear ci.shadowed and initialize ci.ubfreesize
  595.  
  596.     if (lseek(ci.fd,0,SEEK_END) == 0)  // container file empty
  597.     {   ci.sw = 0;
  598.     ci.contpages = 0; 
  599.     }
  600.     else  // read ci.sw, ci.contpages, and ci.fileindex from file
  601.     {   lseek(ci.fd,SWITCH_OFFSET,SEEK_SET);                           // ci.sw
  602.     read(ci.fd,&ci.sw,SIZEOF_INT);
  603.     lseek(ci.fd,contpages_offset(ci.sw),SEEK_SET);                    //ci.contpages
  604.     read(ci.fd,&ci.contpages,SIZEOF_INT);
  605.     for (int i = 0; i < ci.contpages; i += N)            
  606.     {   lseek(ci.fd, pagetable_offset(i,ci.sw), SEEK_SET);
  607.         read(ci.fd, &ci.fileindex[i], N * SIZEOF_INT);
  608.     }
  609.     }
  610.     calculatefreefilepages(ci);
  611.     ci.ubfreesize = MAX_FREEBLOCK_LENGTH; }
  612.     
  613. //------------------------------------------------------------------------------
  614.  
  615. static void writepagetable(containerinfo &ci) 
  616. {
  617.     // toggle ci.sw and write ci.contpages, ci.fileindex to container file
  618.     // recalculate ci.freefilepage and clear ci.shadowed.
  619.  
  620.     ci.sw = !ci.sw;
  621.     lseek(ci.fd, contpages_offset(ci.sw), SEEK_SET);
  622.     write(ci.fd, &ci.contpages, SIZEOF_INT);
  623.     for (int i = 0; i < ci.contpages; i += N) 
  624.     {   lseek(ci.fd, pagetable_offset(i,ci.sw), SEEK_SET);
  625.         write(ci.fd, &ci.fileindex[i], N * SIZEOF_INT); 
  626.     }
  627.     fsync(ci.fd);
  628.     lseek(ci.fd, 0, SEEK_SET);
  629.     write(ci.fd, &ci.sw, SIZEOF_INT);
  630.     calculatefreefilepages(ci);
  631.     ftruncate(ci.fd,fileposition(ci.filepages)); 
  632. }
  633.  
  634. //------------------------------------------------------------------------------
  635.  
  636. static char* containerpath(int id)  // return pointer to path of container id
  637. {
  638.     static char n[MAXPATHLEN];
  639.     char* e = getenv("SOSCONTAINER");
  640.     if (e != 0)
  641.         if (strlen(e) < MAXPATHLEN-12)  // 12=length of containerfile-name
  642.     {
  643.             strcpy(n,e);
  644.             strcat(n,"/");
  645.         sprintf(n + strlen(n),"%d",id);
  646.         return n; 
  647.     }
  648.         else err_raise(err_SYS,err_PSM_PATH_TOO_LONG,ERR,FALSE);
  649.     else err_raise(err_SYS,err_NO_CONTAINER_PATH,ERR,FALSE); 
  650. }
  651.  
  652. //------------------------------------------------------------------------------
  653.  
  654. static void entercontainer(int id, int fd, sos_Access_mode a)
  655. {
  656.     // makes the necessary initializations for the containerinfo ci
  657.     // when opening a new container    
  658.  
  659.     fcntl(fd,F_SETFD,1);                                  // close on exec
  660.     containerinfo &ci = newcontainer(id);
  661.     ci.id = id;
  662.     ci.status = (sos_Container_status) a;
  663.     ci.fd = fd;
  664.     int realpages = uprounded_pagenumber(int(lseek(fd,0,SEEK_END)));
  665.        // total number of file pages
  666.  
  667.     int tablesize = (realpages == 0) ? N
  668.                      : N_upround(realpages);
  669.        // realpages rounded up to a positive multiple of N
  670.  
  671.     ci.conttablesize = tablesize;
  672.     ci.filetablesize = tablesize;
  673.     ci.fileindex = new int[tablesize];
  674.     ci.shadowed = new int[tablesize];
  675.     ci.freefilepage = new int[tablesize];
  676.     ci.freefilepage_index = -1;    // = no freefilepage found
  677.     readpagetable(ci);
  678.     ci.bufferindex = new int[tablesize];
  679.     for (int p = 0; p < ci.contpages; p++) ci.bufferindex[p] = UNDEF;
  680. #ifdef MONITOR
  681.     if (monactivated) 
  682.     {
  683.     ci.win = mon_create(ci.id, ci.contpages);
  684.     char *title;
  685.         if (ci.contpages <= 1) title = strdup ("<new>");
  686.         else
  687.     {
  688.          sos_Object o = sos_Container::make(ci.id).root_object();
  689.         if (o.isa (sos_Named_type))
  690.         title = sos_Named::make(o).get_name().make_Cstring();
  691.         else {
  692.             title = new char [12];
  693.             sprintf(title,"%d",ci.id); }
  694.     }
  695.         mon_open(ci.win,a,title);
  696.     delete title; 
  697.     }
  698. #endif
  699. }
  700.  
  701. //------------------------------------------------------------------------------
  702.  
  703. static void removecontainer(containerinfo &ci)
  704. {
  705.     for (int i = 0; i < B; i++)
  706.         if (buftable[i].id == ci.id)
  707.     {
  708.         buftable[i].id = UNUSED;
  709. #ifdef MONITOR
  710.         if (monactivated) mon_white(ci.win,buftable[i].page);
  711. #endif
  712.         }
  713.     ci.id = UNUSED;
  714.     delete ci.bufferindex;
  715.     delete ci.fileindex;
  716.     delete ci.shadowed;
  717.     delete ci.freefilepage;
  718.     close(ci.fd);   //also unlocks file
  719. #ifdef MONITOR
  720.     if (monactivated) mon_close(ci.win);
  721. #endif
  722.     }
  723.  
  724. //------------------------------------------------------------------------------
  725.  
  726. static void commitcontainer(containerinfo &ci) 
  727. {
  728.     for (int p = 0; p < ci.contpages; p++)
  729.         if (ci.bufferindex[p] != UNDEF && buftable[ci.bufferindex[p]].modified) {
  730.             writepage(ci,p,ci.bufferindex[p]);
  731.             buftable[ci.bufferindex[p]].modified = FALSE; }
  732.     writepagetable(ci); 
  733. }
  734.  
  735. //------------------------------------------------------------------------------
  736.  
  737. static void resetcontainer(containerinfo &ci)
  738. {
  739.     if (ci.status == DESTROYED) ci.status = WRITEABLE;
  740.     // a container could only be destroyed with status WRITEABLE 
  741.  
  742.     for (int p = 0; p < ci.contpages; p++)   // deallocate modified pages in buffer
  743.         if (ci.bufferindex[p] != UNDEF && buftable[ci.bufferindex[p]].modified) 
  744.     {
  745.             buftable[ci.bufferindex[p]].id=UNUSED;
  746.             ci.bufferindex[p] = UNDEF; 
  747.         }
  748.     readpagetable(ci);                      // readpagetable from containerfile
  749. }
  750.  
  751. //------------------------------------------------------------------------------
  752.  
  753. static void squeezecontainer(containerinfo &ci) 
  754. {
  755.     int u = used_pages(ci);
  756.     for (int p = 0; p < ci.contpages; p++)
  757.     if (ci.fileindex[p] >= u)                      // pre : UNDEF < 0
  758.         buftable[lookuppage(ci,p)].modified = TRUE; 
  759.  
  760.     ci.freefilepage_index = -1;    // reset freefilepage_index 
  761.  
  762.     // if it doesn't equal -1 then it happens this in the following commit:
  763.     // the modified pages could be written (see commit -> findfreefilepage ->...)
  764.     // to free pages at the end of the container file
  765.     // => the container will not be truncated (or only parts of) after the commit
  766. }
  767.  
  768. //------------------------------------------------------------------------------
  769.  
  770. static unsigned allocatepages(containerinfo &ci, int n) 
  771. {
  772.     // returns offset of n consecutive free pages and marks them as used
  773.  
  774.     int p = 0, f = 0, s = 0;
  775.     while (s < n  &&  p < ci.contpages)
  776.         if (ci.fileindex[p] == UNDEF) {s++; p++;}
  777.         else {s = 0; p++; f = p;} 
  778.     if (s < n)
  779.     {
  780.         ci.contpages +=  n - s;
  781.         if (ci.conttablesize < ci.contpages)
  782.     {   int newsize = N_upround (ci.contpages);
  783.             extendtable(ci.bufferindex, ci.conttablesize, newsize);
  784.             extendtable(ci.fileindex, ci.conttablesize, newsize);
  785.             extendtable(ci.shadowed, ci.conttablesize, newsize);
  786.             ci.conttablesize = newsize; 
  787.         } 
  788.     }
  789.     for (s = 0; s < n; s++) 
  790.     {   ci.fileindex[f+s] = findfreefilepage(ci);
  791.         ci.shadowed[f+s] = TRUE;
  792.         ci.bufferindex[f+s] = preemptpage(ci.id, f+s);
  793. #ifdef MONITOR
  794.         if (monactivated) mon_black(ci.win,f+s);
  795. #endif
  796.         buftable[ci.bufferindex[f+s]].modified = TRUE;
  797.         bzero(buf[ci.bufferindex[f+s]], P); 
  798.      }
  799.     return f * P; 
  800. }
  801.  
  802. //------------------------------------------------------------------------------
  803.  
  804. static void deallocatepages(containerinfo &ci, int p, int n) 
  805. {
  806.     // mark n consecutive pages starting with page p as unused
  807.  
  808.     while (n > 0) 
  809.     {
  810.     if (ci.shadowed[p]) 
  811.     {     ci.freefilepage[ci.fileindex[p]] = TRUE; 
  812.           // only to shadowed pages because of a possible reset to the container
  813.           ci.shadowed[p] = FALSE; 
  814.     }
  815.     ci.fileindex[p] = UNDEF;
  816.     if (ci.bufferindex[p] != UNDEF) 
  817.     {
  818.           buftable[ci.bufferindex[p]].id = UNUSED;
  819.           ci.bufferindex[p] = UNDEF; 
  820.     }
  821.     n--; p++; 
  822.     } 
  823. }  
  824.  
  825. //------------------------------------------------------------------------------
  826.  
  827. static unsigned size_of_free_blocks(containerinfo &ci) 
  828. {
  829.     int sum = 0;
  830.     for (int sz = 4; sz <= MAX_FREEBLOCK_LENGTH; sz += 4) 
  831.     {  int o = sz;
  832.        while (readint(ci,o) != 0) { // sum all free blocks of size sz
  833.        sum += sz; o = readint(ci,o); }
  834.     }
  835.     return sum;
  836. }
  837.  
  838. //------------------------------------------------------------------------------
  839.  
  840. static unsigned freesize(containerinfo &ci) 
  841. {
  842.     // free size of logical container, not of container file
  843.  
  844.     return (free_pages(ci) * P + size_of_free_blocks(ci));
  845. }
  846.  
  847. //------------------------------------------------------------------------------
  848.  
  849. #ifndef NO_TT
  850.  
  851. // check_freelists checks for a block (given by containerinfo, start and length
  852. // of the block), if it overlaps with a block in the freelist of the container
  853. // (the freelist contains previous deallocated blocks).
  854. // if (_psm_checked_cnt == 0) check all containers
  855. // else                       check only  _psm_checked_cnt
  856.  
  857. const sos_Container _psm_checked_cnt = sos_Container::make (0);
  858.  
  859. void check_freelists (containerinfo &ci, int start, int length)
  860. {  if ( ( _psm_checked_cnt  == 0  ||  _psm_checked_cnt == ci.id)
  861.     &&  ci.id != 0)
  862.    {
  863.        for (int size = 4; size <= MAX_FREEBLOCK_LENGTH; size += 4)  
  864.        {  // iterate over lists of different size
  865.  
  866.       int offset = readint(ci,size);
  867.       while (offset != 0)     
  868.       {
  869.          if ((start >= offset  &&  start < (offset + size)) 
  870.         || (start < offset  &&  (start + length) > offset))
  871.              err_raise(err_SYS,err_PSM_FREELIST_CHECK_FAILED,ERR,FALSE);
  872.          offset = readint(ci,offset);  // next list_element
  873.           }
  874.        }
  875.     }
  876. }
  877.  
  878. #endif NO_TT
  879.  
  880. // ******************************************************************************
  881. //           functions of class sos_Container
  882. // ******************************************************************************
  883. /*
  884. static void sos_Container::compress()
  885. {
  886.    // compress (or merges) blocks of the freelist
  887.  
  888.    containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
  889.  
  890.    int *A = new int[ci.contpages];                        // initialization of A
  891.    for (int i = 0; i < ci.contpages; i++) A[i] = UNDEF;
  892.  
  893.  
  894.    for (int size = 4; size <= MAX_FREEBLOCK_LENGTH; size += 4)  
  895.    {  // Iterate over blocks of the freelist  &  destroy freelists (!)
  896.  
  897.       int current_offset1 = readint(ci,size);  
  898.     // element which will be inserted in list 2
  899.       writeint(ci,size,UNDEF);           // listheader is destroyed
  900.  
  901.       while (current_offset1 != 0)     
  902.       {  next_offset1 = readint(ci,current_offset1);
  903.  
  904.      current_offset2 = A[i];         // offset of current element in list 2
  905.      last_offset2 = 0;               // offset of last    element in list 2
  906.  
  907.      while (current_offset1 > current_offset2  &&  current_offset2 != 0 )  
  908.      { // find right place in list2 to insert
  909.         last_offset2 = current_offset2;
  910.         current_offset2 = readint(ci, current_offset2);
  911.      }
  912.  
  913.      if (current_offset2 == A[i]   // insert at list header (list can be empty)
  914.      {  A[i] = current_offset1;
  915.         writeint(ci, current_offset1, current_offset2);
  916.      }
  917.      else 
  918.      {  if (last_offset == 0) 
  919.            err_raise(err_SYS,err_PSM_COMPRESS,ERR,FALSE); 
  920.         writeint(ci, last_offset2, current_offset1);
  921.         writeint(ci, current_offset1, current_offset2);
  922.      }
  923.  
  924.      current_offset1 = next_offset1;                   // next list element
  925.       }
  926.    }
  927.  
  928.    // Sort & Merge new lists
  929.  
  930.    for ( i = 0; i < ci.contpages; i++)
  931.    {  if (A[i] == UNDEF)
  932.      if (fileindex[i] == UNDEF)
  933.         newfileindex[i] = UNDEF;         // page 'i' is not allocated (used)
  934.      else 
  935.         newfileindex[i] = fileindex[i];  // page contains no free blocks
  936.       else
  937.      if (fileindex[i] == UNDEF)
  938.         err_raise(err_SYS,err_PSM_COMPRESS,ERR,FALSE);
  939.         // page 'i' is not allocated  but contains free blocks
  940.      else 
  941.         merge_blocks(i);
  942.    }
  943.  
  944. // ___ merge blocks
  945.  
  946. void merge_blocks()
  947. {
  948.    offset
  949.  
  950.  
  951.    ???   Problem, da ich Groesse der Bloecke nicht abgspeichert habe
  952.  
  953.    =>  bauche doch explizite andere Datenstruktur (entweder Liste oder Baum)
  954.      in GNU-Bibliotheken ?
  955.  
  956.  
  957.  
  958.  
  959.    delete A;
  960.  
  961. */
  962. //------------------------------------------------------------------------------
  963.  
  964. sos_Container sos_Container::create() 
  965. {
  966.     T_PROC ("sos_Container::create");
  967.     TT (psm_H, T_ENTER);
  968.  
  969.     int id, fd;
  970.     do
  971.     {
  972.         id = (int)(random()%0xfffffd)+2; // 1<id<2^24-1
  973.         fd = ::open(containerpath(id),O_RDWR | O_CREAT | O_EXCL,0664); 
  974.         // owner:rw, group:r others:r
  975.     }
  976.     while (fd == UNDEF  &&  errno == EEXIST);
  977.  
  978.     if (fd == UNDEF) err_raise(err_SYS,err_PSM_CREATE_FAILED,ERR,FALSE);
  979.     lock(fd,WRITING,WAITING);
  980.     entercontainer(id,fd,WRITING);
  981.  
  982.     TT (psm_H, T_LEAVE; TI((int)id));
  983.     return sos_Container::make (id);
  984. }
  985. //------------------------------------------------------------------------------
  986.  
  987. sos_Container_status sos_Container::status() const 
  988. {
  989.     // return status of an opened container  or  UNAVAILABLE, if not opened
  990.  
  991.     T_PROC ("sos_Container::status");
  992.     TT (psm_H, T_ENTER; TI(id));
  993.  
  994.     if (id == 0) err_raise(err_SYS,err_PSM_STATUS_ON_TEMP, ERR,FALSE);
  995.     containerinfo *ct = containertable_pos(id);
  996.  
  997.     sos_Container_status result
  998.        = (ct == (containerinfo *)UNDEF) ? (sos_Container_status) UNAVAILABLE
  999.                     : (sos_Container_status) ct->status;
  1000.  
  1001.     TT (psm_H, T_LEAVE; TI(result));
  1002.     return result;
  1003. }
  1004.  
  1005.    
  1006. //------------------------------------------------------------------------------
  1007.  
  1008. sos_Open_result sos_Container::open(sos_Access_mode a, sos_Sync_mode s) const 
  1009. {
  1010.     T_PROC ("sos_Container::open");
  1011.     TT (psm_H, T_ENTER; TI(id); TI((int)a); TI((int)s));
  1012.  
  1013.     if (id == 0) err_raise(err_SYS,err_PSM_OPEN_ON_TEMP, ERR,FALSE);
  1014.     if ( ! container_is_open(id))  
  1015.     {   int fd = ::open(containerpath(id),O_RDWR,0644); // O_RDWR for upgrading
  1016.         if (fd == UNDEF) 
  1017.     {  TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
  1018.        return UNACCESSIBLE;
  1019.         }
  1020.         if (!lock(fd,a,s)) 
  1021.     {  ::close(fd);
  1022.            TT (psm_H, T_LEAVE; TI((int)LOCKED));
  1023.        return LOCKED;
  1024.         }
  1025.         entercontainer(id,fd,a); 
  1026.     }
  1027.     else
  1028.     {  containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
  1029.        if (ci.status == READABLE  &&  a == WRITING)
  1030.        {  if (!lock(ci.fd,WRITING,s))
  1031.       {
  1032.          // attention if using flock: if exclusive flock fails and
  1033.          // you had an shared flock before then no lock exits
  1034.          // afterwards. Because of that one tries to set again a (new)
  1035.          // shared lock. If this fails -> errormessage
  1036.          // very seldom because between exclusive lock and shared
  1037.          // lock (milliseconds) the following must happen:
  1038.          // the other users with a shared lock must unset their
  1039.          // locks and someone must set an exclusive lock
  1040.           
  1041.          if (!lock(ci.fd,READING,TESTING)) 
  1042.         err_raise(err_SYS,err_PSM_LOST_ALL_LOCKS, ERR,FALSE);
  1043.          TT (psm_H, T_LEAVE; TI((int)LOCKED));
  1044.          return LOCKED;
  1045.       }
  1046.       ci.status = WRITEABLE;
  1047.        }
  1048.    }
  1049.  
  1050.     TT (psm_H, T_LEAVE; TI((int)OPENED));
  1051.     return OPENED;
  1052. }
  1053.  
  1054. //------------------------------------------------------------------------------
  1055.  
  1056. sos_Open_result sos_Container::access(sos_Access_mode a, sos_Sync_mode s) const
  1057. {
  1058.     // only used for upgrading/downgrading
  1059.     // implicit commit if downgrading
  1060.  
  1061.     T_PROC ("sos_Container::access");
  1062.     TT (psm_H, T_ENTER; TI(id); TI((int)a); TI((int)s));
  1063.  
  1064.     if (id == 0) err_raise(err_SYS,err_PSM_ACCESS_ON_TEMP, ERR,FALSE);
  1065.     if ( ! container_is_open(id)) err_raise(err_SYS,err_PSM_NO_ACCESS,ERR,FALSE);
  1066.     containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
  1067.     if (ci.status == WRITEABLE) commitcontainer(ci);
  1068.     if (!lock(ci.fd,a,s))
  1069.       //  attention if using flock (see 20 lines above) if upgrading fails
  1070.       //     you have no lock anymore therefore try again a shared lock
  1071.     {  if (!lock(ci.fd,READING,TESTING)) 
  1072.           err_raise(err_SYS,err_PSM_LOST_ALL_LOCKS, ERR,FALSE); 
  1073.        else if (ci.status == READABLE)  
  1074.        {  TT(psm_H, T_LEAVE; TI((int)LOCKED)); 
  1075.       return LOCKED;
  1076.        }
  1077.     }
  1078.     ci.status = (sos_Container_status) a;
  1079.  
  1080.     TT (psm_H, T_LEAVE; TI((int)OPENED));
  1081.     return OPENED; 
  1082. }
  1083.  
  1084. //------------------------------------------------------------------------------
  1085.  
  1086. void sos_Container::close() const 
  1087. {
  1088.  
  1089.     T_PROC ("sos_Container::close");
  1090.     TT (psm_H, T_ENTER; TI(id));
  1091.  
  1092.     if (id == 0) err_raise(err_SYS,err_PSM_CLOSE_ON_TEMP, ERR,FALSE);
  1093.     containerinfo &ci = lookupcontainer(id,FALSE,FALSE,TRUE);
  1094.     if (ci.status == WRITEABLE) commitcontainer(ci);
  1095.     if (ci.status == DESTROYED) unlink(containerpath(id));
  1096.     removecontainer(ci);
  1097.  
  1098.     TT (psm_H, T_LEAVE); 
  1099. }
  1100.  
  1101. //------------------------------------------------------------------------------
  1102.  
  1103. void sos_Container::destroy() const 
  1104. {
  1105.  
  1106.    T_PROC ("sos_Container::destroy");
  1107.    TT (psm_H, T_ENTER; TI(id));
  1108.  
  1109.    if (id == 0) err_raise(err_SYS,err_PSM_DESTROY_ON_TEMP, ERR,FALSE);
  1110.    containerinfo &ci = lookupcontainer(id,FALSE,TRUE,TRUE);
  1111.    if (ci.status == CHECKEDOUT)    // WRITEABLE and CHECKEDOUT differ only
  1112.                    // in this operation
  1113.       err_raise(err_SYS,err_PSM_DESTROY_DURING_CHECKOUT,ERR,FALSE);
  1114.  
  1115.    if (ci.status != DESTROYED)  
  1116.    {   clear();   //   clear is not necessary, but saves space
  1117.          //   (clear is only called for the first destroy)
  1118.       ci.status = DESTROYED;
  1119.    }
  1120.    TT (psm_H, T_LEAVE); 
  1121. }
  1122.  
  1123. //------------------------------------------------------------------------------
  1124.  
  1125. void sos_Container::commit() const 
  1126. {
  1127.     T_PROC ("sos_Container::commit");
  1128.     TT (psm_H, T_ENTER; TI(id));
  1129.  
  1130.     if (id == 0) err_raise(err_SYS,err_PSM_COMMIT_ON_TEMP, ERR,FALSE);
  1131.     containerinfo& ci = lookupcontainer(id,FALSE,TRUE,TRUE);
  1132.     if (ci.status == DESTROYED) 
  1133.     {
  1134.        unlink(containerpath(id));
  1135.        removecontainer(ci);
  1136.     }
  1137.     else
  1138.        commitcontainer(ci);
  1139.  
  1140.     TT (psm_H, T_LEAVE); 
  1141. }
  1142.  
  1143. //------------------------------------------------------------------------------
  1144.  
  1145. void sos_Container::reset() const 
  1146. {
  1147.     T_PROC ("sos_Container::reset");
  1148.     TT (psm_H, T_ENTER; TI(id));
  1149.  
  1150.     if (id == 0) err_raise(err_SYS,err_PSM_RESET_ON_TEMP, ERR,FALSE);
  1151.     resetcontainer(lookupcontainer(id,FALSE,TRUE,TRUE));
  1152.  
  1153.     TT (psm_H, T_LEAVE); 
  1154. }
  1155.  
  1156. //------------------------------------------------------------------------------
  1157.  
  1158. void sos_Container::squeeze() const 
  1159. {
  1160.     T_PROC ("sos_Container::squeeze");
  1161.     TT (psm_H, T_ENTER; TI(id));
  1162.  
  1163.     if (id == 0) err_raise(err_SYS,err_PSM_COMMIT_ON_TEMP, ERR,FALSE);
  1164.     containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
  1165.     commitcontainer(ci);
  1166.     squeezecontainer(ci);
  1167.     commitcontainer(ci); 
  1168.  
  1169.     TT (psm_H, T_LEAVE); 
  1170. }
  1171.  
  1172. //------------------------------------------------------------------------------
  1173.  
  1174. unsigned sos_Container::allocate(unsigned size) const 
  1175. {
  1176.  
  1177.     T_PROC ("sos_Container::allocate");
  1178.     TT (psm_M, T_ENTER; TI(id); TI(size) );
  1179.  
  1180.     unsigned result;
  1181.  
  1182.     if (size == 0) err_raise(err_SYS,err_PSM_ALLOC_NULL_BYTES,ERR,FALSE);
  1183.     if (id == 0)
  1184.     {  result = (unsigned) new char [size];
  1185.        if (result == 0) err_raise(err_SYS,err_PSM_TEMP_FULL,ERR,FALSE);
  1186.     }
  1187.    else
  1188.    {  containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
  1189.       if (ci.contpages == 0)  // allocate page with table of free blocks
  1190.       {  allocatepages(ci,1);
  1191.          ci.ubfreesize = 0; 
  1192.       }
  1193.       if (size <= MAX_FREEBLOCK_LENGTH)
  1194.       {  // lookup in table of free blocks, which stands in the first
  1195.      // page of the container
  1196.      // ( lists of free blocks are only used in :
  1197.      //   allocate/deallocate, size_of_free_blocks, check_free_lists,
  1198.      //   (object_exists)  )
  1199.  
  1200.          size=rounded(size);
  1201.      result = readint(ci,size);
  1202.          if (result != 0)  // free block of identical size exists
  1203.             writeint(ci,size,readint(ci,result)); 
  1204.          else  // try to find block of larger size, starting at size
  1205.      {  int sz = size + 4;    // sz > size
  1206.             while (sz <= ci.ubfreesize  &&  readint(ci,sz) == 0)
  1207.            sz += 4;
  1208.             if (sz <= ci.ubfreesize)               // readint(ci,sz) != 0
  1209.         {  result = readint(ci,sz);
  1210.  
  1211.            // new first list element
  1212.            writeint(ci,sz,readint(ci,result));  
  1213.  
  1214.            // insert rest of bigger block (of length sz - size) in table of
  1215.            // free blocks
  1216.            writeint(ci,result+size,readint(ci,sz - size));
  1217.            writeint(ci,sz - size,result + size); 
  1218.         }
  1219.         else                                  // sz > ci.ubfreesize  
  1220.         {  result = allocatepages(ci,1);
  1221.  
  1222.            // insert rest of page in table of free blocks
  1223.            writeint(ci,result + size,readint(ci,P - size));
  1224.            writeint(ci,P - size,result + size);
  1225.            ci.ubfreesize = max(ci.ubfreesize, P-size); 
  1226.         }
  1227.      } 
  1228.       }
  1229.       else result = allocatepages(ci, uprounded_pagenumber(size)); 
  1230.    }
  1231.  
  1232.    TT (psm_M, T_LEAVE; TI(result));
  1233.    return result;
  1234. }
  1235.  
  1236. //----------------------------------------------------------------------------
  1237.     
  1238. void sos_Container::deallocate(sos_Offset o, unsigned size) const 
  1239. {
  1240.     T_PROC ("sos_Container::deallocate");
  1241.     TT (psm_M, T_ENTER; ; TI(id); TI(o); TI(size));
  1242.     
  1243.     if (size == 0)  err_raise(err_SYS,err_PSM_DEALLOC_NULL_BYTES,ERR,FALSE);
  1244.     if (id == 0) delete (char*) o;
  1245.     else 
  1246.       if (o < 1024) err_raise(err_SYS,err_PSM_DEALLOCATE_WRONG_OFFSET, ERR,FALSE); 
  1247.     else 
  1248.     {  containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
  1249.        TTN (psm_CHECK_WRITE, check_freelists (ci, o, size));
  1250.        if (size <= MAX_FREEBLOCK_LENGTH)     //enter in table of free blocks
  1251.        {   size = rounded(size);
  1252.        writeint(ci,o,readint(ci,size));  // link together with list 
  1253.        writeint(ci,size,o);
  1254.        ci.ubfreesize = max(ci.ubfreesize,size); 
  1255.  
  1256.        if (size >= 8)   writeint(ci,o+SIZEOF_INT,UNDEF); 
  1257.        //flag to indicate, that object is deleted:necessary for object_exists()
  1258.        }
  1259.        else deallocatepages(ci,o/P,uprounded_pagenumber(size)); 
  1260.     }
  1261.  
  1262.     TT (psm_M, T_LEAVE) 
  1263. }
  1264.  
  1265. //--------------------------------------------------------------------------
  1266.  
  1267. int sos_Container::modified() const 
  1268.    // return whether sos_Container has been modified since last commit
  1269.    // not implemented by status-bit because then in many functions this bit 
  1270.    // must be set/unset
  1271.    // type of returnvalue not of type sos_Bool because  psm.h must
  1272.    // stand before  knl_use.h and  forward enum-declaration is not possible
  1273.    // container must be opened
  1274.  
  1275.    T_PROC ("sos_Container::modified");
  1276.    TT (psm_H, T_ENTER; TI(id));
  1277.  
  1278.    if (id == 0) err_raise(err_SYS,err_PSM_MODIFIED_ON_TEMP, ERR,FALSE); 
  1279.    containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
  1280.  
  1281.    if (ci.status == WRITEABLE  ||  ci.status == CHECKEDOUT)
  1282.       for (int p = 0; p < ci.contpages; p++)   
  1283.          if (ci.bufferindex[p] != UNDEF  &&  buftable[ci.bufferindex[p]].modified)
  1284.      {  TT (psm_H, T_LEAVE; TI(TRUE));
  1285.         return TRUE;                      // at least one page is  modified
  1286.      }
  1287.  
  1288.    TT (psm_H, T_LEAVE; TI(FALSE));
  1289.    return FALSE;            //  read-only   or   not opened    or   not modified
  1290. }
  1291.  
  1292. //--------------------------------------------------------------------------
  1293.  
  1294. int sos_Container::exists() const 
  1295. {
  1296.    // returns whether container exists
  1297.    // or not (i.e., file is destroyed  or  container has been destroyed, but the
  1298.    // operation has been not yet  committed)
  1299.  
  1300.    T_PROC ("sos_Container::exists");
  1301.    TT (psm_H, T_ENTER; TI(id));
  1302.  
  1303.    int result = FALSE;          // modified 24/10/91 (bs)
  1304.  
  1305.    switch (status())
  1306.    {
  1307.       case READABLE:
  1308.       case WRITEABLE:
  1309.       case CHECKEDOUT:  result = TRUE;
  1310.                         break;
  1311.  
  1312.       case DESTROYED:   result = FALSE;
  1313.                         break;
  1314.  
  1315.       case UNAVAILABLE: int fd = ::open(containerpath(id),O_RDONLY);
  1316.             if (fd != UNDEF) 
  1317.             {  ::close(fd);
  1318.                result = TRUE;
  1319.             }
  1320.                         break;
  1321.        default:  err_raise(err_SYS,err_PSM_EXISTS,ERR,FALSE);
  1322.          break;
  1323.    };
  1324.    TT (psm_H, T_LEAVE; TI(result));
  1325.    return result; 
  1326. }
  1327.  
  1328. //--------------------------------------------------------------------------
  1329.  
  1330. int sos_Container::deleted() const
  1331.    // returns whether file ,which belongs to container, is deleted or not
  1332.  
  1333.    T_PROC ("sos_Container::deleted"); TT (psm_H, T_ENTER; TI(id));
  1334.    TT (psm_H, T_LEAVE; TI(!exists())); 
  1335.    return (! exists());
  1336. }
  1337. //--------------------------------------------------------------------------
  1338.  
  1339. sos_Existing_status sos_Container::object_exists(sos_Offset o, unsigned size) const 
  1340. {
  1341.    // returns whether the object exists (perhaps) or not (sure)
  1342.    // pre: offset & size belongs to former objects in that container
  1343.    // else access outside allocated area is possible
  1344.    // (no TRACE inserted because of the many return statements)
  1345.  
  1346.    int flag;
  1347.  
  1348.    if (id == 0)  return PERHAPS_EXISTING;                 // temporary container
  1349.    if ( rounded(size) < 8) return PERHAPS_EXISTING;       // no sos_Object
  1350.    if (o < 1024) return NOT_EXISTING;                     // wrong offset
  1351.  
  1352.    if (! container_is_open(id))                  // container-file(!) not opened
  1353.    {  // now similar statements as in entercontainer      //   or not existing
  1354.  
  1355.       int sw,contpages;
  1356.       int fd = ::open(containerpath(id),O_RDONLY); 
  1357.  
  1358.       if (fd == UNDEF) return NOT_EXISTING;               // file does not exist
  1359.  
  1360.       lseek(fd, SWITCH_OFFSET,SEEK_SET);                     // switch
  1361.       ::read(fd,&sw,SIZEOF_INT);
  1362.  
  1363.       lseek(fd,contpages_offset(sw),SEEK_SET);               // number of contpages
  1364.       ::read(fd,&contpages,SIZEOF_INT);
  1365.  
  1366.       if (contpages == 0)  return NOT_EXISTING;           // container file empty
  1367.  
  1368.       int contpage = o / P;                               // logical container page
  1369.       if (contpage > contpages) return NOT_EXISTING; 
  1370.  
  1371.       // pagetable_offset in containerfile  +  page_offset inside pagetable
  1372.       lseek(fd, pagetable_offset(contpage,sw) + (contpage%N) * SIZEOF_INT, SEEK_SET);
  1373.       ::read(fd,&contpage,SIZEOF_INT);                   // page in file
  1374.  
  1375.       if (size <= MAX_FREEBLOCK_LENGTH) 
  1376.       {  if (contpage==UNDEF)  return NOT_EXISTING;   // WRONG_OFFSET
  1377.  
  1378.      lseek(fd,fileposition(contpage) + o%P + SIZEOF_INT,SEEK_SET); //offset in file
  1379.        // fileposition(contpage) + offset inside of page
  1380.        //  + SIZEOF_INT (for special bytes (=flagbyte) extra for this function)
  1381.      ::read(fd,&flag,SIZEOF_INT);
  1382.      return (flag == UNDEF) ? NOT_EXISTING : PERHAPS_EXISTING;
  1383.       }
  1384.       else  // look only at first of (possibly) several pages because of efficiency
  1385.       {  
  1386.      return (contpage == UNDEF)  ? NOT_EXISTING : PERHAPS_EXISTING;
  1387.       }
  1388.    }
  1389.    else                                                // container opened 
  1390.    {  containerinfo &ci = lookupcontainer(id,FALSE,FALSE,TRUE);
  1391.       if (sos_Container_status(ci.status) == DESTROYED) return NOT_EXISTING;
  1392.       if (size <= MAX_FREEBLOCK_LENGTH)  
  1393.       {  // offset 'cannot' be wrong (see:precondition)  because never
  1394.          // merge free blocks to greater free blocks (pages) 
  1395.  
  1396.       if (uprounded_pagenumber(o + size) > ci.contpages) return NOT_EXISTING;  
  1397.       flag = readint(ci, o + SIZEOF_INT );   
  1398.       return (flag == UNDEF) ? NOT_EXISTING : PERHAPS_EXISTING;  
  1399.       }
  1400.       else    // if one of the pages is UNDEF or no more existing (>contapges)
  1401.       {       // => object is  NOT_EXISTING
  1402.  
  1403.      if (o % P != 0) return NOT_EXISTING;   // offset must be a multiple of P
  1404.          int upper_bound = uprounded_pagenumber(o + size);
  1405.      for (int p = o/P; p < upper_bound; p++)
  1406.         if ((p > ci.contpages) || (ci.fileindex[p] == UNDEF)) return NOT_EXISTING;
  1407.  
  1408.          return PERHAPS_EXISTING;
  1409.       }
  1410.    }
  1411. }
  1412.  
  1413. //--------------------------------------------------------------------------
  1414.  
  1415. sos_Open_result sos_Container::checkout(sos_Access_mode, sos_Sync_mode) const
  1416. {
  1417.    err_raise_not_implemented ("sos_Container::checkout (will be realized by sos_Container::open(CHECKOUT, sync_mode)");
  1418.    return UNACCESSIBLE;
  1419. }
  1420.  
  1421. //--------------------------------------------------------------------------
  1422.  
  1423. unsigned sos_Container::rounded(unsigned size) const
  1424. {
  1425.     return (unsigned) (((size+3) /4) *4); 
  1426. }
  1427.  
  1428. //--------------------------------------------------------------------------
  1429.  
  1430. void sos_Container::clear() const 
  1431. {
  1432.     T_PROC ("sos_Container::clear");
  1433.     TT (psm_H, T_ENTER; TI(id));
  1434.  
  1435.     if (id == 0) err_raise(err_SYS,err_PSM_CLEAR_ON_TEMP, ERR,FALSE);
  1436.     containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
  1437.     deallocatepages(ci,0,ci.contpages);
  1438.     ci.contpages = 0; 
  1439.     
  1440.     TT (psm_H, T_LEAVE); 
  1441. }
  1442.  
  1443. //--------------------------------------------------------------------------
  1444.  
  1445. unsigned sos_Container::occupied() const 
  1446. {
  1447.     // occupied bytes (data which is referenced from fileindex) in the container file
  1448.  
  1449.     T_PROC ("sos_Container::occupied");
  1450.     TT (psm_H, T_ENTER; TI(id));
  1451.  
  1452.     if (id == 0) err_raise(err_SYS,err_PSM_EMPTY_ON_TEMP, ERR,FALSE);
  1453.     containerinfo &ci = lookupcontainer(id,FALSE,FALSE);
  1454.  
  1455.     // substract from used_pages all free blocks and first page (table of 
  1456.     // free blocks)
  1457.  
  1458.     TT (psm_H, T_LEAVE); 
  1459.     return (ci.contpages == 0 ? 0 : used_pages(ci)*P - size_of_free_blocks(ci) - P);
  1460. }
  1461.  
  1462. //--------------------------------------------------------------------------
  1463.  
  1464. void sos_Container::read(sos_Offset o, unsigned size, void* data) const 
  1465. {
  1466.     T_PROC ("sos_Container::read");
  1467.     TT (psm_M, T_ENTER; TI(id); TI(o); TI(size); TP(data));
  1468.  
  1469.     if (id == 0) bcopy((char*)o,data,size);
  1470.     else if (size > 0)
  1471.     {   containerinfo &ci = lookupcontainer(id,TRUE,FALSE);
  1472.         TTN (psm_CHECK_READ, check_freelists (ci, o, size));
  1473.  
  1474.     char *d = (char*)data;
  1475.     int  len;
  1476.         while (1)
  1477.     {   int disp = o % P; // displacement in page
  1478.  
  1479.         if ((len = P-disp) >= size)
  1480.         {  readfrompage(ci,o/P,disp,size,d);
  1481.            break;
  1482.         }
  1483.             readfrompage(ci,o/P,disp,len,d);
  1484.             o += len;    
  1485.             d += len; 
  1486.         size -= len; }
  1487.         } 
  1488.  
  1489.     TT (psm_M, T_LEAVE); 
  1490. }
  1491.  
  1492. //--------------------------------------------------------------------------
  1493.  
  1494. void sos_Container::write(sos_Offset o, unsigned size, void* data) const 
  1495. {
  1496.    T_PROC ("sos_Container::write");
  1497.    TT (psm_M, T_ENTER; TI(id); TI(o); TI(size); TP(data));
  1498.  
  1499.    if (id == 0) bcopy(data,(char*)o,size);
  1500.    else 
  1501.    {  char *d = (char*)data;
  1502.       containerinfo &ci = lookupcontainer(id,FALSE,TRUE);
  1503.       TTN (psm_CHECK_WRITE, check_freelists (ci, o, size));
  1504.       while (size > 0)
  1505.       {
  1506.       int disp = o%P; // displacement in page
  1507.       int len = min(size, P-disp);
  1508.       writetopage(ci,o/P,disp,len,d);
  1509.       o += len;    
  1510.       d += len;
  1511.       size -= len; 
  1512.       } 
  1513.    } 
  1514.  
  1515.    TT (psm_M, T_LEAVE); 
  1516. }
  1517.  
  1518. //--------------------------------------------------------------------------
  1519.  
  1520. void sos_Container::copy(sos_Offset o1, unsigned size, sos_Container c2,
  1521.     sos_Offset o2) const 
  1522. {
  1523.     T_PROC ("sos_Container::copy");
  1524.     TT (psm_M, T_ENTER; TI(id); TI(o1); TI(size); TI((int)c2); TI(o2));
  1525.  
  1526.     containerinfo *ci1 = containertable,*ci2 = containertable;
  1527.     int d1,d2;
  1528.     char *a1,*a2;
  1529.     if (id != 0) ci1 = &lookupcontainer(id,TRUE,FALSE);
  1530.     if (c2.id != 0) ci2 = &lookupcontainer(c2.id,FALSE,TRUE);
  1531.     if (o1 > o2) //copy from low to high
  1532.         while (size > 0) 
  1533.     {
  1534.             if (id == 0) {d1 = 0; a1 = (char*) o1;}
  1535.             else {d1 = o1 % P; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
  1536.             if (c2.id == 0) {d2 = 0; a2 = (char*) o2;}
  1537.             else 
  1538.         {   d2 = o2 % P;
  1539.                 int destbufpage = lookuppage(*ci2,o2/P);
  1540.                 a2 = buf[destbufpage] + d2;
  1541.                 buftable[destbufpage].modified = TRUE;
  1542.         }
  1543.             int len = min(size,min(P-d1,P-d2));
  1544.             bcopy(a1,a2,len);
  1545.             o1 += len; o2 += len; size -= len; 
  1546.         }
  1547.     else  //copy from high to low
  1548.     {   o1 += size - 1; o2 += size - 1;
  1549.         while (size > 0) 
  1550.     {   if (id == 0) {d1 = P; a1 = (char*) o1 + 1;}
  1551.             else {d1 = o1%P + 1; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
  1552.             if (c2.id == 0) {d2 = P; a2 = (char*) o2 + 1;}
  1553.             else 
  1554.         {
  1555.                 d2 = o2%P + 1;
  1556.                 int destbufpage = lookuppage(*ci2,o2/P);
  1557.                 a2 = buf[destbufpage] + d2;
  1558.                 buftable[destbufpage].modified = TRUE; 
  1559.         }
  1560.             int len = min(size,min(d1,d2));
  1561.             bcopy(a1-len,a2-len,len);
  1562.             o1 -= len; o2 -= len; size -= len; 
  1563.         } 
  1564.    }
  1565.  
  1566.     TT (psm_M, T_LEAVE); 
  1567. }
  1568.  
  1569. //--------------------------------------------------------------------------
  1570.  
  1571. int sos_Container::equal(sos_Offset o1, unsigned size, sos_Container c2,
  1572.     sos_Offset o2) const 
  1573. {
  1574.     T_PROC ("sos_Container::equal");
  1575.     TT (psm_M, T_ENTER; TI(id); TI(o1); TI(size); TI((int)c2); TI(o2));
  1576.  
  1577.     containerinfo *ci1 = containertable,*ci2 = containertable;
  1578.     int d1,d2;
  1579.     char *a1,*a2;
  1580.     if (id == 0) d1 = 0; else ci1 = &lookupcontainer(id,TRUE,FALSE);
  1581.     if (c2.id == 0) d2 = 0; else ci2 = &lookupcontainer(c2.id,TRUE,FALSE);
  1582.     while (size > 0) 
  1583.     {   if (id == 0) a1 = (char*) o1;
  1584.         else {d1 = o1%P; a1 = buf[lookuppage(*ci1,o1/P)] + d1; }
  1585.         if (c2.id == 0) a2 = (char*) o2;
  1586.         else {d2 = o2%P; a2 = buf[lookuppage(*ci2,o2/P)] + d2; }
  1587.         int len = min(size,min(P-d1,P-d2));
  1588.         if (bcmp(a1,a2,len) != 0) 
  1589.     {  TT(psm_M, T_LEAVE; TI(FALSE));
  1590.        return FALSE;
  1591.     }
  1592.         o1 += len; o2 += len; size -= len; 
  1593.     }
  1594.  
  1595.     TT(psm_M, T_LEAVE; TI(TRUE));
  1596.     return TRUE; 
  1597. }
  1598.  
  1599. //--------------------------------------------------------------------------
  1600.  
  1601. int sos_Container::hash_value (sos_Offset o, unsigned size) const 
  1602. {
  1603.     T_PROC ("sos_Container::hash_value");
  1604.     TT (psm_H, T_ENTER; TI(id); TI(o); TI(size));
  1605.  
  1606.     unsigned u = o + size;
  1607.     unsigned l = SIZEOF_INT;
  1608.     int result = 0;
  1609.     int data;
  1610.     for ( ; o < u; o += l) 
  1611.     {   if (l > u - o) { l = u - o; data = 0; } // if size is not a multiple 
  1612.                                                 // of SIZEOF_INT
  1613.         read (o, l, &data);
  1614.         result ^= data; 
  1615.     }
  1616.     TT(psm_H, T_LEAVE; TI(result));
  1617.     return result; 
  1618. }
  1619.  
  1620. //--------------------------------------------------------------------------
  1621.  
  1622. sos_Object sos_Container::root_object() const 
  1623. {
  1624.   return sos_Object::make (sos_Typed_id::make (sos_Id::make (*this, ROOT_OFFSET))); 
  1625. }
  1626.  
  1627. // ********************************************************************
  1628. //              functions of class sos_Container_set
  1629. // ********************************************************************
  1630.  
  1631. /*
  1632. // copy constructors do not worrk correctly for the gnu-compilers  !!!
  1633. sos_Container_set::sos_Container_set(const sos_Container_set& cs)
  1634. {
  1635.     size = cs.size;
  1636.     n = cs.n;
  1637.     s = new int[size];
  1638.     int* s2 = cs.s;
  1639.     for (int i = 0; i < n; ++i)
  1640.        *s++ = *s2++;
  1641. }
  1642.  
  1643.  
  1644. sos_Container_set& sos_Container_set::operator=(const sos_Container_set& cs)
  1645. {
  1646.     size = cs.size;
  1647.     n = cs.n;
  1648.     s = new int[size];
  1649.     int* s2 = cs.s;
  1650.     for (int i = 0; i < n; ++i)
  1651.        *s++ = *s2++;
  1652.     
  1653.     // during test , after program termination clobbereed space detected
  1654.     // also false results (false container in set)
  1655.     // during compilation: warning because of bitwise ...
  1656.     // psmtest.c:7: warning: bitwise copy: `sos_Container_set' defines operator=()
  1657. }
  1658.  
  1659. */
  1660.  
  1661. sos_Container_set::sos_Container_set() 
  1662. {
  1663.     T_PROC ("sos_Container_set::sos_Container_set");
  1664.     TT (psm_H, T_ENTER);
  1665.  
  1666.     size = 16;
  1667.     s = new int[size];
  1668.     n = 0; 
  1669.  
  1670.     TT (psm_H, T_LEAVE);
  1671. }
  1672.  
  1673. sos_Container_set::~sos_Container_set()
  1674. // { delete [size] s; } // must be inserted again (after presentation)
  1675. {
  1676. }
  1677.  
  1678. sos_Container_set& sos_Container_set::operator+=(sos_Container c) 
  1679. {
  1680.     T_PROC ("sos_Container_set::operator+=");
  1681.     TT (psm_H, T_ENTER);
  1682.  
  1683.     if ( c == TEMP_CONTAINER) err_raise(err_SYS,err_PSM_ADD_WITH_TEMP, ERR,FALSE);
  1684.     if (n == size) {extendtable(s,size,2*size); size *= 2; }
  1685.     TT (psm_H, T_LEAVE);
  1686.     for (int i = 0; i < n; ++i)   // multiple appearance of the same container
  1687.        if (s[i] == c)           // in one set (not bag!) not allowed
  1688.       return *this;
  1689.     s[n] = (int)c; n++; return *this; 
  1690. }
  1691.  
  1692. sos_Open_result sos_Container_set::op(int i,const sos_Container_set& rd,const  
  1693.            sos_Container_set& wr, sos_Sync_mode s) 
  1694. {
  1695.     if (i < rd.card()) return sos_Container::make(rd.s[i]).open(READING,s);
  1696.     else return sos_Container::make(wr.s[i-rd.n]).open(WRITING,s); 
  1697. }
  1698.  
  1699. void sos_Container_set::cl(int i,const sos_Container_set& rd,const sos_Container_set& wr) 
  1700. {
  1701.     if (i < rd.card()) sos_Container::make(rd.s[i]).close();
  1702.     else sos_Container::make(wr.s[i-rd.n]).close(); 
  1703. }
  1704.  
  1705. sos_Open_result sos_Container_set::open(const sos_Container_set& rd, 
  1706.       const sos_Container_set& wr, sos_Sync_mode s)
  1707. {
  1708.     T_PROC ("sos_Container_set::open");
  1709.     TT (psm_H, T_ENTER);
  1710.  
  1711.     int i = 0;
  1712.     while (i <  rd.card() + wr.card())
  1713.  
  1714.         switch (sos_Container_set::op(i,rd,wr,TESTING)) {
  1715.             case OPENED: i++; break;
  1716.             case UNACCESSIBLE:
  1717.                 for (int j = 0; j < i; j++) sos_Container_set::cl(j,rd,wr);
  1718.                 TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
  1719.                 return UNACCESSIBLE;
  1720.             case LOCKED:
  1721.                 for (int k = 0; k < i; k++) sos_Container_set::cl(k,rd,wr);
  1722.                 if (s == TESTING) 
  1723.         {   TT (psm_H, T_LEAVE; TI((int)LOCKED));
  1724.            return LOCKED;
  1725.         }
  1726.                 switch (sos_Container_set::op(i,rd,wr,WAITING)) {
  1727.                     case UNACCESSIBLE:  TT (psm_H, T_LEAVE; TI((int)UNACCESSIBLE));
  1728.                                        return UNACCESSIBLE;
  1729.                     case OPENED: sos_Container_set::cl(i,rd,wr); i = 0; } }
  1730.  
  1731.     TT (psm_H, T_LEAVE; TI((int)OPENED));
  1732.     return OPENED; 
  1733. }
  1734.  
  1735. //--------------------------------------------------------------------------
  1736.  
  1737. sos_Container_set& sos_Container_set::open_containers(sos_Container_status stat)
  1738. {
  1739.    // returns set of containers openend for WRITING/READING dependent on status
  1740.  
  1741.    T_PROC ("sos_Container_set::open_containers");
  1742.    TT (psm_H, T_ENTER);
  1743.  
  1744.    sos_Container_set* new_set = new sos_Container_set;
  1745.    for (int i = 0; i < C; i++) 
  1746.    {
  1747.     if ((containertable[i].id != UNUSED) && (containertable[i].status == stat))
  1748.             (*new_set) += sos_Container::make(containertable[i].id);
  1749.    }
  1750.    TT (psm_H, T_LEAVE);
  1751.    return (*new_set);
  1752. }
  1753.  
  1754. //--------------------------------------------------------------------------
  1755.  
  1756. sos_Open_result sos_Container_set::open(sos_Access_mode a, sos_Sync_mode s) const 
  1757. {
  1758.     sos_Container_set empty;
  1759.     if (a == READING) return sos_Container_set::open(*this,empty,s);
  1760.     else return sos_Container_set::open(empty,*this,s); 
  1761. }
  1762.  
  1763. //--------------------------------------------------------------------------
  1764.  
  1765. void sos_Container_set::close() const
  1766. {
  1767.     T_PROC ("sos_Container_set::close"); TT (psm_H, T_ENTER);
  1768.     for (int i = 0; i < card(); i++) sos_Container::make(s[i]).close(); 
  1769.     TT(psm_H, T_LEAVE);
  1770. }
  1771.  
  1772. //--------------------------------------------------------------------------
  1773.  
  1774. void sos_Container_set::commit() const 
  1775. {
  1776.     T_PROC ("sos_Container_set::commit"); TT (psm_H, T_ENTER);
  1777.     for (int i = 0; i < card(); i++) sos_Container::make(s[i]).commit(); 
  1778.     TT(psm_H, T_LEAVE);
  1779. }
  1780.  
  1781. //--------------------------------------------------------------------------
  1782.  
  1783. void sos_Container_set::reset() const 
  1784. {
  1785.     T_PROC ("sos_Container_set::reset"); TT (psm_H, T_ENTER);
  1786.     for (int i = 0; i < card(); i++) sos_Container::make(s[i]).reset(); 
  1787.     TT(psm_H, T_LEAVE);
  1788. }
  1789.  
  1790. // ************  sos_Container_set and sos_Container_cursor  *******************
  1791.  
  1792. sos_Container_cursor sos_Container_set::open_cursor() const 
  1793. {
  1794.    // creates a new cursor-object and positions it to the first element
  1795.    // if one exists
  1796.  
  1797.    T_PROC ("sos_Container_set::open_cursor"); TT (psm_L, T_ENTER);
  1798.    sos_Container_cursor new_c;
  1799.    new_c.idx = (card() > 0) ? 0 : -1 ;
  1800.    TT (psm_L, T_LEAVE; TI(new_c.idx));
  1801.    return new_c;
  1802. }
  1803.  
  1804. //--------------------------------------------------------------------------
  1805.  
  1806. void sos_Container_set::close_cursor (sos_Container_cursor &c) const 
  1807.    T_PROC ("sos_Container_set::close_cursor"); TT (psm_L, T_ENTER);
  1808.    c.idx = -1;
  1809.    TT (psm_L, T_LEAVE);
  1810.    return;
  1811. }
  1812.  
  1813. //--------------------------------------------------------------------------
  1814.  
  1815. int sos_Container_set::to_succ (sos_Container_cursor& c) const 
  1816. {  
  1817.    // moves cursor one position further and return FALSE, if 'end of 
  1818.    // set' is reached, else TRUE
  1819.    T_PROC ("sos_Container_set::to_succ"); TT (psm_L, T_ENTER);
  1820.  
  1821.    if ( ++c.idx >= card() ) 
  1822.    {  c.idx = -1;
  1823.       TT (psm_L, T_LEAVE; TI(FALSE));
  1824.       return FALSE;
  1825.    } 
  1826.    else 
  1827.    {  TT (psm_L, T_LEAVE; TI(TRUE));
  1828.       return TRUE;
  1829.    }
  1830.  
  1831. //--------------------------------------------------------------------------
  1832.  
  1833. int sos_Container_set::is_valid (sos_Container_cursor c) const 
  1834.    T_PROC ("sos_Container_set::is_valid"); TT (psm_L, T_ENTER);
  1835.    TT (psm_L, T_LEAVE);
  1836.    return (c.idx >= 0  &&  c.idx < card());  
  1837. }
  1838.  
  1839. //--------------------------------------------------------------------------
  1840.  
  1841. sos_Container sos_Container_set::get (sos_Container_cursor c) const 
  1842. {
  1843.    T_PROC ("sos_Container_set::get"); TT (psm_L, T_ENTER);
  1844.    if ( ! this->is_valid(c))  err_raise(err_SYS,err_PSM_INVALID_CURSOR, ERR,FALSE); 
  1845.    TT (psm_L, T_LEAVE);
  1846.    return sos_Container::make(s[c.idx]);
  1847. }
  1848.  
  1849. //----------------------------------------------------------------------------
  1850. /*  TRACE generates for the functions of class sos_Container and sos_Container_set
  1851.     (and for function lock()) the following output:
  1852.  
  1853.        T_ENTER: name of function, container id  and all arguments of the function
  1854.        T_LEAVE: name of function and return argument
  1855.     
  1856.     exceptions for T_LEAVE 
  1857.        - no output of return argument :  status, occupied, lock, get, is_valid
  1858.     exceptions for T_ENTER
  1859.        - no output of id : create
  1860.  
  1861.     exception for TRACE at all: object_exists
  1862. */
  1863. //----------------------------------------------------------------------------
  1864. /*
  1865.  
  1866. //--------- to do for release SOS3-2 ----------------------------------
  1867.  
  1868.  - SOSBUFFERSIZE  - wo dokumentieren, wo ist SOS_MONITOR dokumentiert ???
  1869.  
  1870. --------- POSTPONED -------------
  1871.  
  1872. - destruktor fuer contaiener_set =>   .... Implementierung von container_set wie
  1873.     bei smg_string
  1874.  
  1875. - in object_exists Funktion readint_from_file herausfaktorisieren 
  1876.  
  1877.   EFFIZIENZTEST FUER INLINE ... (einmal fast nichts, einmal fast alle
  1878.   hilfsfkt. inline)
  1879.   - moeglichst viele Hilfsfunktonen  inline deklarieren => nur fuer die
  1880.   Hilfsfunktionen wird einmal Code angelegt bzw. so hauefig, we sie in den
  1881.   Interfacefunktionen vorkommen. Wie oft die Schnittstellenfunktionen aufgerufen
  1882.   werden, ist voellig egal, dort steht ja nur ein Funktionsaufruf.
  1883.  
  1884. - effizienzv improvement for read() ... with no use of bcopy
  1885.     (in read() ... replace bcopy, if size <=16, ...)
  1886.  
  1887. - compress
  1888.  
  1889. sos_Container als sos_Objects :
  1890.   ? Klasse als Schnittstelle darueberlegen
  1891.   ? sind containersets richtig implementiert :
  1892.      falls der Anwender unterprogramm mit paramater (nicht &) uerbergibt wird
  1893.      beim ruecksprung cnt_set zerstoert   und    wenn dem Anwender set
  1894.      uebergeben wird und dieser sein Programm beendet (macht nichts. da set nur
  1895.      im hauptspeicher ?!
  1896.  
  1897.      wie ist dies in SOS realisiert: referenzcounter, der bei 'copy' mitzaehlt
  1898.      wieviele referenzen auf dieses aggragate existieren und erst bei 0 dieses
  1899.      loescht
  1900.  
  1901. --------  DONE  ---------
  1902.  
  1903. - globale unix-variable fuer sosbuffersize
  1904.    - Benutzer kann sich selbst groesse waeheln
  1905.    - Zeitmessungen moeglich
  1906.  
  1907. - interne Funktionen verbessern bzw. erzeugen
  1908.    z.B. container_exists...
  1909.  
  1910. - sos_Access_mode/sos_CONtainer_status klar trennen .status/ c.status() / ...
  1911.  
  1912. - MAX_FREEBLOPCVKLENGTH = P-8 ersetzen durch P-4,   size oder rounded(size) <=
  1913. MAX... ist egal ...
  1914.  
  1915. - sos-gsh als test vom psm durchfuehren
  1916.  
  1917.   - checkout-Funktionsheader nicht direkjt loeschen, sondern durch Fehlermeldung
  1918.   " not implemented ..." ersetzzen"  und in keinem Fall in der Manpage
  1919.   erwaaehnen
  1920.  
  1921. - manpages aktualisieren und an vielen Stellen ausfuhrlivcher beschreiben
  1922.   - neue TRC-Switches psm_check_erad/write in Manpage beschreiben
  1923.  
  1924. - Destroy: siehe File "Destroy"
  1925.  
  1926. - Effizienz fuer sehr grosse Container ?
  1927.   Da das Laden der seitentabelle viel Zeit kostet (fuer groose Container) und
  1928.   auch das Zurueckschreiben bei commit, koenen auch kleine Aenderungen am
  1929.   Containerinhalt viel Zeit kosten (falls Container gross).
  1930.   Kann man dies verbessern?
  1931.  
  1932.   Beim Zurueckschreiben: nicht nur ein Switch fuer alle Teile der Seitentabelle
  1933.   verwalten, sondern fuer jeden Teil ein extra-Switch und ein Gesamt-Switch.
  1934.   Dadurch mueste man nur noch ein Byte (oder 4) statt 1024 Byte schreiben, falls
  1935.   sich der zugehoerige Teil der seitentabelle nicht geaendert hat. Mehraufwand
  1936.   waehren ein paar Abfragen ( ? und pruefen, welche Teile der Seitentabelle von
  1937.   den Aederungen betroffen sind ?). Lohnt sich sicher nur fuer sehr grosse
  1938.   Container, die daher nicht zu oft geoeefnet und geschlossen werden sollten.
  1939.  
  1940.   Beim Oeffnen des Containers: Die Seitentabelle musste "lazy" geladen weren,
  1941.   dass heisst die betreffenden Teile wereen nur dann in den Hauptspeicher
  1942.   geladen, wenn erforderlich. => viel komplizierter unf lohnt sich wirklich nur
  1943.   fuer sehr grosse Files (koennte man durch die Laenge der Seitentabelle anfangs
  1944.   abfragen und vielleicht als parameter beim oeffnen mitgeben: normal_open
  1945.   or 'open_with_lazy_changes"
  1946.  
  1947.  
  1948.  
  1949. */
  1950. //-----------------------------------------------------------------------------
  1951. // end of psm.c
  1952. //-----------------------------------------------------------------------------
  1953.  
  1954.